/*
 * Planificador.c
 *
 *  Created on: 18/09/2011
 *      Author: utn_so
 */
#include "Planificador.h"

int IniciarSocketListen()
{
	 int32_t sockfd=1;
	    int32_t optval;

	    optval = 1;
	    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	    {
	        printf("No se pudo crear el socket General \n");
	        return -1;
	    }

	    struct sockaddr_in my_addr;                /*    informaci�n sobre mi direcci�n    */
	    my_addr.sin_family = AF_INET;             /*    Ordenaci�n de bytes de la m�quina    */
	    my_addr.sin_port = htons(atoi(buscacfg("SOCKGRAL-PORT")));         /*    short, Ordenaci�n de bytes de la red    */
	    my_addr.sin_addr.s_addr = INADDR_ANY;     /*    Rellenar con mi direcci�n IP */

	    memset(&(my_addr.sin_zero), '\0', 8);    /*    Poner a cero el resto de la estructura    */
	    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);
	    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))== -1)
	        {
	        printf("Error en el bind(), initSockFSS() en socket.c\n");
	        return -1;
	        }

	    if ( listen(sockfd, 5) < 0 )
	       {
	       printf("Error en el listen(), initSock() en socket.c\n");
	       return -1;
	       }
	    return sockfd;
}

int32_t conectar(char* ip, int32_t puerto)
{
	sockRAID=0;
    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port = htons(puerto);
    server.sin_addr.s_addr = inet_addr(ip);
    memset(&(server.sin_zero), '\0', 8);

    sockRAID = socket(AF_INET, SOCK_STREAM, 0);
    if (sockRAID == -1){
	   printf("Error socket(), en conectar() en socket.c");
        return -1;}

    if (connect(sockRAID, (struct sockaddr*)&server, sizeof (struct sockaddr)) == -1)
		{printf( "Error connect(), en conectar() dentro de socket.c");
        return -1;}
    else
    {
    	escribir_logfile("DiscoSO", 0, INFOs, "Conectado a proceso RAID");
    	short length = 10;
    	Paquete *unPaquete = malloc(sizeof(Paquete));
    	unPaquete->Tipo='0';
    	RandomGG(unPaquete->ID,16);
    	unPaquete->Length=length;
    	unPaquete->Sector=(atoi(ArrayConfAlgoritmo[5])*atoi(ArrayConfAlgoritmo[12]));
    	unPaquete->Datos=buscacfg("Nombre");
    	//Serializar Paquete
    	//Serializar(unPaquete);
    	//DesSerializar(Serializar(unPaquete));
		char* serial ;
		serial = Serializar(unPaquete);
    	if(send(sockRAID,serial,10+1+16+2+4,0)==-1)
    		printf("FalloSEND");
    	else
    	{
    		char* recvBuff = malloc(16+1+2+1+4);
    		int32_t rc=recv(sockRAID,recvBuff,16+1+2+1+4,0);
    		if(rc > 0)
    		{
    			unPaquete = DesSerializar(recvBuff);
    			escribir_logfile("DiscoSO", 0, INFOs, "HandShake Proceso RAID");
    			//printf("HandShake con Proceso RAID \n");
    		}
    		free(recvBuff);
    	}
		free(serial);
		free(unPaquete);
    }
	return 0;
}

void RandomGG(char dst[16], int32_t size)
{
   static const char text[] = "abcdefghijklmnopqrstuvwxyz"
		   	   	   	   	   	  "0123456789"
                              "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
   int32_t i, len = (size);
   for ( i = 0; i < len; ++i )
   {
      dst[i] = text[rand() % (sizeof text - 1)];
   }
}


///Serializa el contenido de una struc Paquete. Transforma todo en un char* de memoria contigua.
/// La funcion retorna un char* que debera ser enviado por el send correspondiente.
char* Serializar(Paquete* unPaquete)
{
	char* retorno =malloc( 16 + 1 + 2 + 4 + (unPaquete->Length));
	memcpy(retorno,&unPaquete->ID,16);
	memcpy(retorno+16,&unPaquete->Sector,4);
    memcpy(retorno+16+4,&unPaquete->Tipo,1);
	memcpy(retorno+1+16+4,&unPaquete->Length,2);
	memcpy(retorno+1+16+2+4,unPaquete->Datos,unPaquete->Length);
	return retorno;
}

/// DesSerializa un char* resultante de una serializacion, a una struct Paquete.
/// Recibe un stream (el q va a venir del RECV) y lo transforma en un "Paquete"
Paquete* DesSerializar(char *unStream)
{
	Paquete* unPaquete=malloc(sizeof(Paquete));
	memcpy(&unPaquete->ID,unStream,16);
	memcpy(&unPaquete->Sector,unStream+16,4);
    memcpy(&unPaquete->Tipo,unStream+16+4,1);
	memcpy(&unPaquete->Length,unStream+1+16+4,2);
	unPaquete->Datos=malloc(unPaquete->Length);
	memcpy(unPaquete->Datos,unStream+16+1+2+4,unPaquete->Length);
	return unPaquete;
}

void IniciarDisco()
{
	char* ruta = malloc(100);
	strcat(ruta,"/home/utn_so/");
	strcat(ruta,buscacfg("Nombre"));
	strcat(ruta,".disk");
	archDisco = fopen(ruta,"r+");
	int32_t fd = fileno_unlocked(archDisco);
	posix_fadvise(fd,0,0,0);
	if(archDisco==NULL)
		printf("Error abriendo el archivo disco.\n");
}

void* InicializarCola()
{
	char* recvBuff = malloc(1+16+2+512+4);
	escribir_logfile("DiscoSO", 0, INFOs, "Colas Inicializadas");
	int xx=0;
	for(xx=0;xx<TAMANO_COLA;xx++)
	{
		ColaPedidos[xx].Tipo='0';
		ColaPedidos[xx].Sector=-1;
	}
	int32_t buscaSocket=0;
	int32_t fdmax=0;
	fd_set read_fds;
	fd_set master;
	if(strcmp(ArrayConfAlgoritmo[0],"LISTEN")==0)
	{
		FD_ZERO(&read_fds);
		FD_ZERO(&master);
		FD_SET(sockGral,&master);
		fdmax=sockGral;
	}
	else
	{
		FD_ZERO(&master);
		sockGral=-3;
		FD_ZERO(&read_fds);
		FD_SET(sockRAID,&master);
		fdmax=sockRAID;
	}


	while(1)
	{
		read_fds=master;
		if(select(fdmax+1,&read_fds,NULL,NULL,NULL)== -1)
		{
			printf("error en conexiones /n");
		}
		for(buscaSocket = 0; buscaSocket <=fdmax+1;buscaSocket++)
		{
			if(FD_ISSET(buscaSocket, &read_fds))
			{
				if(buscaSocket== sockGral)
				{
					sockRAID = accept(sockGral,NULL,NULL);
					Handshake();
					FD_SET(sockRAID,&master);
					if(sockRAID>fdmax)
						fdmax=sockRAID;
				}
				else
				{
					int x=0;
					//sleep(0,1);
					pthread_mutex_lock (&mutexBuffer);
					///encolar pedidos que recibe del "sockRAID"
					int32_t rc=-1;
					//if(recv(buscaSocket,recvBuff,1+16+2+512+4,MSG_PEEK | MSG_DONTWAIT)>=535)
					//{
						//sleep(1);
						rc =recv(buscaSocket,recvBuff,1+16+2+512+4,MSG_WAITALL);
						if(rc > 0)
						{
							Paquete* unPaquete ;
							unPaquete = DesSerializar(recvBuff);
							pthread_mutex_unlock (&mutexBuffer);
							Solicitud unaSolicitud;
							//sleep(2);
							//printf("\n Encolando pedido sector %d , %d \n ",unPaquete->Sector,rc);
							if(unPaquete->Tipo=='E')
							{
								for(x=0;x<512;x++)
									unaSolicitud.Datos[x]=unPaquete->Datos[x];
							}
							else
							{
								for(x=0;x<512;x++)
									unaSolicitud.Datos[x]='\0';
							}
							for(x=0;x<16;x++)
								unaSolicitud.ID[x]=unPaquete->ID[x];
							unaSolicitud.Sector=unPaquete->Sector;
							unaSolicitud.Tipo=unPaquete->Tipo;
							unaSolicitud.Socket=buscaSocket;
							pthread_mutex_lock(&mutexEncolar);
							EncolarPedido(unaSolicitud);
							//printf("Encolando pedido %d \n" , unaSolicitud.Sector);
							pthread_mutex_unlock(&mutexEncolar);
							free(unPaquete->Datos);
							free(unPaquete);
						//}
						//else
						//	pthread_mutex_unlock (&mutexBuffer);
					}
					else
						pthread_mutex_unlock (&mutexBuffer);
				}
			}
		}
	}
}

void IniciarColas()
{
	char* message;
	int32_t  iCola;
	iCola=pthread_create( &HiloCola, NULL, InicializarCola,(void*) message);
}

int32_t EscribirSector(int32_t posicion,unsigned char* stream)
{
	int32_t i = 0;
	fseek(archDisco,512*posicion,0);
	for(i=0;i<512;i++)
	{
		if(fputc_unlocked(stream[i],archDisco)==EOF)
			return -1;
	}pthread_mutex_lock (&mutexCabezal);
	Cabezal=posicion+1;

	if(Cabezal==((atoi(ArrayConfAlgoritmo[5]))*(atoi(ArrayConfAlgoritmo[12]))))
	{
		Cabezal=0;
	}
	pthread_mutex_unlock (&mutexCabezal);
	return 0;

}

int32_t LeerSector(int32_t sector)
{

	fseek(archDisco,512*sector,0);
	/*for(i=0;i<512;i++)
	{
		printable=(fgetc_unlocked(archDisco));
		if(printable=='\0')
			printf("\\0");
		else if(printable=='\n')
			printf("\\n\n");
		else
			printf("%c",printable);
	}
	printf("\n");*/
	pthread_mutex_lock (&mutexCabezal);
	Cabezal=sector +1;

	if(Cabezal==((atoi(ArrayConfAlgoritmo[5]))*(atoi(ArrayConfAlgoritmo[12]))))
	{
		Cabezal=0;
	}
	pthread_mutex_unlock (&mutexCabezal);
	return 0;
}

int32_t LeerSectorLlenar(int32_t sector, unsigned char* datos)
{
	unsigned char printable='\0';
	int32_t i = 0;
	fseek(archDisco,512*sector,0);
	for(i=0;i<512;i++)
	{
		printable=(fgetc_unlocked(archDisco));
		/*if(printable=='\0')
			printf("\\0");
		else if(printable=='\n')
			printf("\\n\n");
		else
			printf("%c",printable);*/
		datos[i]=printable;
	}
	pthread_mutex_lock (&mutexCabezal);
	Cabezal=sector +1;
	pthread_mutex_unlock (&mutexCabezal);
	/*printf("\n");*/
	return 0;
}

